﻿using System;
using System.Linq;
using HK.Core.Common;
using HK.Core.Common.Data;
using HK.Core.Common.Protocol;
using HK.Core.Common.Protocol.Data;
using HK.Core.Extend;
using HK.Core.GUIEx.Protocol.Attribute;
using HK.Core.Serializable.Attribute;
using HK.Core.Serializable.Data;
using HK.Core.Settings.Protocol;
using HK.Core.Utils;
using UnityEngine;
using UnityEngine.Rendering;

namespace HK.Core.Settings.Data
{
    /// <summary>
    /// 环境光设定
    /// </summary>
    [Serializable]
    public sealed class AmbientSettings : JsonData<AmbientSettings>, IAmbientSettings
    {

#region Create
        
        /// <summary>
        /// 创建环境光设定
        /// </summary>
        /// <returns>环境光设定</returns>
        public static AmbientSettings Create()
        {
            return new AmbientSettings();
        }

        /// <summary>
        /// 创建环境光设定
        /// </summary>
        /// <param name="iMode">光照模式</param>
        /// <param name="iEquatorColor">侧面环境光</param>
        /// <param name="iGroundColor">下方环境光</param>
        /// <param name="iSkyColor">上方环境光</param>
        /// <param name="iLight">平面环境光照颜色</param>
        /// <param name="iIntensity">环境光强度</param>
        /// <returns>环境光设定</returns>
        public static AmbientSettings Create(AmbientMode iMode, Color iEquatorColor, 
            Color iGroundColor, Color iSkyColor, Color iLight, float iIntensity)
        {
            return new AmbientSettings
            {
                Mode = iMode, EquatorColor = iEquatorColor, GroundColor = iGroundColor, 
                SkyColor = iSkyColor, Light = iLight, Intensity = iIntensity
            };
        }

#endregion
        
        /// <summary>
        /// 保护构造函数
        /// </summary>
        private AmbientSettings() {}
        
        [SerializeField, GenericField("模式", null, "Unity 可以提供几种环境光照模式，例如具有独立天空、赤道和地面颜色的方向环境或具有一种颜色的平面环境。")]
        private AmbientMode mode = AmbientMode.Skybox;
        /// <summary>
        /// 光照模式
        /// <para>* Unity 可以提供几种环境光照模式，例如具有独立天空、赤道和地面颜色的方向环境或具有一种颜色的平面环境。</para>
        /// </summary>
        public AmbientMode Mode 
        {
            get => mode;
            internal set => mode = value;
        }
        
        [SerializeField, GenericField("侧面光", null, "Trilight 环境光照模式使用此颜色影响朝向侧面的对象部分。\n在平面环境光照模式中，赤道颜色只是单一的环境颜色，并且与 ambientLight 的值相同。")]
        private Color equatorColor = Color.clear;
        /// <summary>
        /// 侧面环境光
        /// <para>* Trilight 环境光照模式使用此颜色影响朝向侧面的对象部分。</para>
        /// <para>* 在平面环境光照模式中，赤道颜色只是单一的环境颜色，并且与 ambientLight 的值相同。</para>
        /// </summary>
        public Color EquatorColor
        {
            get => equatorColor;
            internal set => equatorColor = value;
        }
        
        [SerializeField, GenericField("下方光", null, "Trilight 环境光照模式使用此颜色影响朝向下方的对象部分。")]
        private Color groundColor = Color.clear;
        /// <summary>
        /// 下方环境光
        /// <para>* Trilight 环境光照模式使用此颜色影响朝向下方的对象部分。</para>
        /// </summary>
        public Color GroundColor 
        {
            get => groundColor;
            internal set => groundColor = value;
        }
        
        [SerializeField, GenericField("上方光", null, "Trilight 环境光照模式使用此颜色影响朝向上方的对象部分。")]
        private Color skyColor = Color.clear;
        /// <summary>
        /// 上方环境光
        /// <para>* Trilight 环境光照模式使用此颜色影响朝向上方的对象部分。</para>
        /// </summary>
        public Color SkyColor 
        {
            get => skyColor;
            internal set => skyColor = value;
        }
        
        [SerializeField, GenericField("平面环境光", null, "平面环境光照模式会使用颜色，其值与 ambientSkyColor 的值相同")]
        private Color light = Color.clear;
        /// <summary>
        /// 平面环境光照颜色
        /// <para>* 平面环境光照模式会使用颜色，其值与 ambientSkyColor 的值相同</para>
        /// </summary>
        public Color Light 
        {
            get => light;
            internal set => light = value;
        }
        
        [SerializeField, GenericField("强度", null, "来自环境光源的光照会对场景产生多大的影响")]
        private float intensity = 0.0f;
        /// <summary>
        /// 环境光强度
        /// <para>* 来自环境光源的光照会对场景产生多大的影响</para>
        /// </summary>
        public float Intensity 
        {
            get => intensity;
            internal set => intensity = value;
        }

        /// <summary>
        /// 应用数据
        /// </summary>
        /// <param name="iData">数据</param>
        /// <param name="iImport">导入标志位(true:从相应的*.json文件导入; false:反之;)</param>
        /// <returns>true:有变更; false:无变更;</returns>
        public override bool ApplyData(IJsonData iData, bool iImport = false)
        {
            if (null == iData || !iData.Valid) return false;
            var dirty = base.ApplyData(iData, iImport);
            if (dirty && !iImport)
            {
                Dirty = true;
            }

            if (iData is IAmbientSettings settings)
            {
                mode = UpdateValue(mode, settings.Mode, iImport);
                equatorColor = UpdateValue(equatorColor, settings.EquatorColor, iImport);
                groundColor = UpdateValue(groundColor, settings.GroundColor, iImport);
                skyColor = UpdateValue(skyColor, settings.SkyColor, iImport);
                light = UpdateValue(light, settings.Light, iImport);
                intensity = UpdateValue(intensity, settings.Intensity, iImport);
            }

            return Dirty;
        }
        
        /// <summary>
        /// 更新值
        /// </summary>
        /// <param name="iCurValue">当前值</param>
        /// <param name="iDstValue">目标值</param>
        /// <param name="iImport">导入标志位</param>
        /// <returns>可以更新的值</returns>
        private AmbientMode UpdateValue(AmbientMode iCurValue, AmbientMode iDstValue, bool iImport)
        {
            var dirty = iCurValue != iDstValue;
            if (dirty && !iImport)
            {
                Dirty = true;
            }

            return dirty ? iDstValue : iCurValue;
        }   

        /// <summary>
        /// 清空
        /// </summary>
        public override void Clear()
        {
            base.Clear();
            
            mode = AmbientMode.Skybox;
            equatorColor = Color.clear;
            groundColor = Color.clear;
            skyColor = Color.clear;
            light = Color.clear;
            intensity = 0.0f;
        }
    }

    /// <summary>
    /// 光晕设定
    /// </summary>
    [Serializable]
    public sealed class FlareSettings : JsonData<FlareSettings>, IFlareSettings
    {

#region Create

        /// <summary>
        /// 创建光晕设定
        /// </summary>
        /// <returns>光晕设定</returns>
        public static FlareSettings Create()
        {
            return new FlareSettings();
        }

        /// <summary>
        /// 创建光晕设定
        /// </summary>
        /// <param name="iFadeSpeed">光晕的淡化速度</param>
        /// <param name="iStrength">光晕强度</param>
        /// <returns>光晕设定</returns>
        public static FlareSettings Create(float iFadeSpeed, float iStrength)
        {
            return new FlareSettings { FadeSpeed = iFadeSpeed, Strength = iStrength };
        }

#endregion
        
        /// <summary>
        /// 保护构造函数
        /// </summary>
        private FlareSettings() {}
        
        [SerializeField, GenericField("淡化速度", null, "场景中所有光晕的淡化速度")]
        private float fadeSpeed = 0.0f;
        /// <summary>
        /// 光晕的淡化速度
        /// <para>* 场景中所有光晕的淡化速度</para>
        /// </summary>
        public float FadeSpeed
        {
            get => fadeSpeed;
            internal set => fadeSpeed = value;
        }
        
        [SerializeField, GenericField("强度", null, "场景中所有光晕的强度")]
        private float strength = 0.0f;
        /// <summary>
        /// 光晕强度
        /// <para>* 场景中所有光晕的强度</para>
        /// </summary>
        public float Strength 
        {
            get => strength;
            internal set => strength = value;
        }

        /// <summary>
        /// 应用数据
        /// </summary>
        /// <param name="iData">数据</param>
        /// <param name="iImport">导入标志位(true:从相应的*.json文件导入; false:反之;)</param>
        /// <returns>true:有变更; false:无变更;</returns>
        public override bool ApplyData(IJsonData iData, bool iImport = false)
        {
            if (null == iData || !iData.Valid) return false;
            var dirty = base.ApplyData(iData, iImport);
            if (dirty && !iImport)
            {
                Dirty = true;
            }

            if (iData is IFlareSettings settings)
            {
                fadeSpeed = UpdateValue(fadeSpeed, settings.FadeSpeed, iImport);
                strength = UpdateValue(strength, settings.Strength, iImport);
            }

            return Dirty;
        }

        /// <summary>
        /// 清空
        /// </summary>
        public override void Clear()
        {
            base.Clear();
            
            fadeSpeed = 0.0f;
            strength = 0.0f;
        }
    }

    /// <summary>
    /// 雾效设定
    /// </summary>
    [Serializable]
    public sealed class FogSettings : JsonData<FogSettings>, IFogSettings
    {

#region Create

        /// <summary>
        /// 创建无效设定
        /// </summary>
        /// <returns>雾效设定</returns>
        public static FogSettings Create()
        {
            return new FogSettings();
        }

        /// <summary>
        /// 创建无效设定
        /// </summary>
        /// <param name="iMode">雾效模式</param>
        /// <param name="iFog">雾效开启</param>
        /// <param name="iColor">雾效颜色</param>
        /// <param name="iDensity">雾效密度</param>
        /// <param name="iStartDistance">雾效开始距离</param>
        /// <param name="iEndDistance">雾效结束距离</param>
        /// <returns>雾效设定</returns>
        public static FogSettings Create(FogMode iMode, bool iFog, Color iColor, 
            float iDensity, float iStartDistance, float iEndDistance)
        {
            return new FogSettings
            {
                Mode = iMode, Fog = iFog, Color = iColor, Density = iDensity,
                StartDistance = iStartDistance, EndDistance = iEndDistance
            };
        }

#endregion
        
        /// <summary>
        /// 保护构造函数
        /// </summary>
        private FogSettings() {}
        
        [SerializeField, GenericField("开启")]
        private bool fog = false;
        /// <summary>
        /// 雾效开启标志位
        /// </summary>
        public bool Fog 
        {
            get => fog;
            internal set => fog = value;
        }

        [SerializeField, GenericField("模式", null, "另请参阅：RenderSettings.fogMode、Lighting 窗口。")]
        private FogMode mode = FogMode.Linear;
        /// <summary>
        /// 雾效模式
        /// <para>* 另请参阅：RenderSettings.fogMode、Lighting 窗口。</para>
        /// </summary>
        public FogMode Mode 
        {
            get => mode;
            internal set => mode = value;
        }
        
        [SerializeField, GenericField("雾色")]
        private Color color = Color.clear;
        /// <summary>
        /// 雾效颜色
        /// </summary>
        public Color Color 
        {
            get => color;
            internal set => color = value;
        }

        [SerializeField, GenericField("密度", null, "Exponential 和 ExponentialSquared 模式会使用雾效强度")]
        private float density = 0.0f;
        /// <summary>
        /// 雾效密度
        /// <para>* Exponential 和 ExponentialSquared 模式会使用雾效强度。</para>
        /// </summary>
        public float Density 
        {
            get => density;
            internal set => density = value;
        }

        [SerializeField, GenericField("开始距离", null, "Linear 雾效模式会使用雾效开始和结束距离。\n另请参阅：RenderSettings.fogEndDistance、RenderSettings.fogMode。")]
        private float startDistance = 0.0f;
        /// <summary>
        /// 雾效开始距离
        /// <para>* Linear 雾效模式会使用雾效开始和结束距离。</para>
        /// <para>* 另请参阅：RenderSettings.fogEndDistance、RenderSettings.fogMode。</para>
        /// </summary>
        public float StartDistance 
        {
            get => startDistance;
            internal set => startDistance = value;
        }
        
        [SerializeField, GenericField("结束距离", null, "Linear 雾效模式会使用雾效开始和结束距离。\n另请参阅：RenderSettings.fogEndDistance、RenderSettings.fogMode。")]
        private float endDistance = 0.0f;
        /// <summary>
        /// 雾效结束距离
        /// <para>* Linear 雾效模式会使用雾效开始和结束距离。</para>
        /// <para>* 另请参阅：RenderSettings.fogEndDistance、RenderSettings.fogMode。</para>
        /// </summary>
        public float EndDistance 
        {
            get => endDistance;
            internal set => endDistance = value;
        }

        /// <summary>
        /// 应用数据
        /// </summary>
        /// <param name="iData">数据</param>
        /// <param name="iImport">导入标志位(true:从相应的*.json文件导入; false:反之;)</param>
        /// <returns>true:有变更; false:无变更;</returns>
        public override bool ApplyData(IJsonData iData, bool iImport = false)
        {
            if (null == iData || !iData.Valid) return false;
            var dirty = base.ApplyData(iData, iImport);
            if (dirty && !iImport)
            {
                Dirty = true;
            }

            if (iData is IFogSettings settings)
            {
                mode = UpdateValue(mode, settings.Mode, iImport);
                fog = UpdateValue(fog, settings.Fog, iImport);
                color = UpdateValue(color, settings.Color, iImport);
                density = UpdateValue(density, settings.Density, iImport);
                startDistance = UpdateValue(startDistance, settings.StartDistance, iImport);
                endDistance = UpdateValue(endDistance, settings.EndDistance, iImport);
            }

            return Dirty;
        }
        
        /// <summary>
        /// 更新值
        /// </summary>
        /// <param name="iCurValue">当前值</param>
        /// <param name="iDstValue">目标值</param>
        /// <param name="iImport">导入标志位</param>
        /// <returns>可以更新的值</returns>
        private FogMode UpdateValue(FogMode iCurValue, FogMode iDstValue, bool iImport)
        {
            var dirty = iCurValue != iDstValue;
            if (dirty && !iImport)
            {
                Dirty = true;
            }

            return dirty ? iDstValue : iCurValue;
        }

        /// <summary>
        /// 清空
        /// </summary>
        public override void Clear()
        {
            base.Clear();
            
            mode = FogMode.Linear;
            fog = false;
            color = Color.clear;
            density = 0.0f;
            startDistance = 0.0f;
            endDistance = 0.0f;
        }
    }

    /// <summary>
    /// 反射设定
    /// </summary>
    [Serializable]
    public sealed class ReflectionSettings : JsonData<ReflectionSettings>, IReflectionSettings
    {

#region Create

        /// <summary>
        /// 创建反射设定
        /// </summary>
        /// <returns>反射设定</returns>
        public static ReflectionSettings Create()
        {
            return new ReflectionSettings();
        }
        
        /// <summary>
        /// 创建反射设定
        /// </summary>
        /// <param name="iDefaultMode">默认模式</param>
        /// <param name="iBounces">反射次数</param>
        /// <param name="iIntensity">反射强度</param>
        /// <returns>反射设定</returns>
        public static ReflectionSettings Create(DefaultReflectionMode iDefaultMode, int iBounces, float iIntensity)
        {
            return new ReflectionSettings
            {
                DefaultMode = iDefaultMode, Bounces = iBounces, Intensity = iIntensity
            };
        }

#endregion
        
        /// <summary>
        /// 保护构造函数
        /// </summary>
        private ReflectionSettings() {}
        
        [SerializeField, GenericField("次数", null, "定义有多少通道计算了反射。在一个给定通道中，场景会渲染到一个立方体贴图中，并将在上个通道中计算的反射应用到反射对象。\n如果设置为 1，场景将被渲染一次。这意味着反射将不能反射其他反射，并且当在其他反射表面看到反射对象时，反射对象将显示为黑色。\n如果设置为 2，场景将被渲染两次，并且当在其他反射表面看到反射对象时，反射对象会显示来自第一个通道的反射。")]
        private int bounces = 1;
        /// <summary>
        /// 反射的次数。
        /// <para>* 定义有多少通道计算了反射。在一个给定通道中，场景会渲染到一个立方体贴图中，并将在上个通道中计算的反射应用到反射对象。</para>
        /// <para>* 如果设置为 1，场景将被渲染一次。这意味着反射将不能反射其他反射，并且当在其他反射表面看到反射对象时，反射对象将显示为黑色。</para>
        /// <para>* 如果设置为 2，场景将被渲染两次，并且当在其他反射表面看到反射对象时，反射对象会显示来自第一个通道的反射。</para>
        /// </summary>
        public int Bounces
        {
            get => bounces;
            internal set => bounces = value;
        }

        [SerializeField, GenericField("强度", null, "天空盒/自定义立方体贴图反射会对场景产生多大的影响。")]
        private float intensity = 0.0f;
        /// <summary>
        /// 反射强度
        /// <para>* 天空盒/自定义立方体贴图反射会对场景产生多大的影响。</para>
        /// </summary>
        public float Intensity 
        {
            get => intensity;
            internal set => intensity = value;
        }

        [SerializeField, GenericField("默认模式", null, "Unity 可以使用自定义纹理或从天空盒中生成镜面反射纹理。")]
        private DefaultReflectionMode defaultMode = DefaultReflectionMode.Skybox;
        /// <summary>
        /// 默认反射模式
        /// <para>* Unity 可以使用自定义纹理或从天空盒中生成镜面反射纹理。</para>
        /// </summary>
        public DefaultReflectionMode DefaultMode 
        {
            get => defaultMode;
            internal set => defaultMode = value;
        }

        /// <summary>
        /// 应用数据
        /// </summary>
        /// <param name="iData">数据</param>
        /// <param name="iImport">导入标志位(true:从相应的*.json文件导入; false:反之;)</param>
        /// <returns>true:有变更; false:无变更;</returns>
        public override bool ApplyData(IJsonData iData, bool iImport = false)
        {
            if (null == iData || !iData.Valid) return false;
            var dirty = base.ApplyData(iData, iImport);
            if (dirty && !iImport)
            {
                Dirty = true;
            }

            if (iData is IReflectionSettings settings)
            {
                bounces = UpdateValue(bounces, settings.Bounces, iImport);
                intensity = UpdateValue(intensity, settings.Intensity, iImport);
                defaultMode = UpdateValue(defaultMode, settings.DefaultMode, iImport);
            }

            return Dirty;
        }
        
        /// <summary>
        /// 更新值
        /// </summary>
        /// <param name="iCurValue">当前值</param>
        /// <param name="iDstValue">目标值</param>
        /// <param name="iImport">导入标志位</param>
        /// <returns>可以更新的值</returns>
        private DefaultReflectionMode UpdateValue(DefaultReflectionMode iCurValue, DefaultReflectionMode iDstValue, bool iImport)
        {
            var dirty = iCurValue != iDstValue;
            if (dirty && !iImport)
            {
                Dirty = true;
            }

            return dirty ? iDstValue : iCurValue;
        }   

        /// <summary>
        /// 清空
        /// </summary>
        public override void Clear()
        {
            base.Clear();
            
            bounces = 1;
            intensity = 0.0f;
            defaultMode = DefaultReflectionMode.Skybox;
        }
    }

    /// <summary>
    /// 场景渲染设定
    /// <para>* 详情参考 : https://docs.unity3d.com/cn/current/ScriptReference/RenderSettings.html</para>
    /// </summary>
    [Serializable]
    public sealed class SceneRenderSettingsData : JsonData<SceneRenderSettingsData>, ISceneRenderSettingsData, IEquatable<SceneRenderSettingsData>
    {

#region Create

        /// <summary>
        /// 创建场景渲染设定信息
        /// </summary>
        /// <param name="iSceneName">场景名</param>
        /// <param name="iAmbient">环境光设定</param>
        /// <param name="iFlare">光晕设定</param>
        /// <param name="iFog">雾效设定</param>
        /// <param name="iReflection">反射设定</param>
        /// <param name="iHaloStrength">Light光环的大小</param>
        /// <param name="iSubtractiveShadowColor">Subtractive 光照模式下太阳阴影使用的颜色</param>
        /// <returns>场景渲染设定信息</returns>
        public static SceneRenderSettingsData Create(string iSceneName, AmbientSettings iAmbient, 
            FlareSettings iFlare, FogSettings iFog, ReflectionSettings iReflection,
            float iHaloStrength, Color iSubtractiveShadowColor)
        {
            return new SceneRenderSettingsData
            {
                SceneName = iSceneName, ambientSettings = iAmbient, flareSettings = iFlare, 
                fogSettings = iFog, reflectionSettings = iReflection, HaloStrength = iHaloStrength, 
                subtractiveShadowColor = iSubtractiveShadowColor
            };
        }

#endregion
        
        /// <summary>
        /// 保护构造函数
        /// </summary>
        private SceneRenderSettingsData() {}

        [SerializeField, GenericField("场景名", (int)GUIOperateOptions.ReadOnlyGenericField)]
        private string sceneName = null;
        /// <summary>
        /// 场景名
        /// </summary>
        public string SceneName
        {
            get => sceneName;
            private set => sceneName = value;
        }
        
        /// <summary>
        /// 唯一标识Element的Key
        /// </summary>
        public string Key => sceneName;
        
#region Ambient

        [SerializeField, GroupView("环境光设定")]
        private AmbientSettings ambientSettings = Data.AmbientSettings.Create();
        /// <summary>
        /// 环境光设定
        /// </summary>
        public IAmbientSettings AmbientSettings => ambientSettings;
        
        /// <summary>
        /// 光照模式
        /// <para>* Unity 可以提供几种环境光照模式，例如具有独立天空、赤道和地面颜色的方向环境或具有一种颜色的平面环境。</para>
        /// </summary>
        public AmbientMode AmbientMode 
        {
            get => ambientSettings.Mode;
            set => ambientSettings.Mode = value;
        }

        /// <summary>
        /// 侧面环境光
        /// <para>* Trilight 环境光照模式使用此颜色影响朝向侧面的对象部分。</para>
        /// <para>* 在平面环境光照模式中，赤道颜色只是单一的环境颜色，并且与 ambientLight 的值相同。</para>
        /// </summary>
        public Color AmbientEquatorColor
        {
            get => ambientSettings.EquatorColor;
            set => ambientSettings.EquatorColor = value;
        }
        
        /// <summary>
        /// 下方环境光
        /// <para>* Trilight 环境光照模式使用此颜色影响朝向下方的对象部分。</para>
        /// </summary>
        public Color AmbientGroundColor 
        {
            get => ambientSettings.GroundColor;
            set => ambientSettings.GroundColor = value;
        }
        
        /// <summary>
        /// 上方环境光
        /// <para>* Trilight 环境光照模式使用此颜色影响朝向上方的对象部分。</para>
        /// </summary>
        public Color AmbientSkyColor 
        {
            get => ambientSettings.SkyColor;
            set => ambientSettings.SkyColor = value;
        }
        
        /// <summary>
        /// 平面环境光照颜色
        /// <para>* 平面环境光照模式会使用颜色，其值与 ambientSkyColor 的值相同</para>
        /// </summary>
        public Color AmbientLight 
        {
            get => ambientSettings.Light;
            set => ambientSettings.Light = value;
        }
        
        /// <summary>
        /// 环境光强度
        /// <para>* 来自环境光源的光照会对场景产生多大的影响</para>
        /// </summary>
        public float AmbientIntensity 
        {
            get => ambientSettings.Intensity;
            set => ambientSettings.Intensity = value;
        }

#endregion

#region Flare

        [SerializeField, GroupView("光晕设定")]
        private FlareSettings flareSettings = Data.FlareSettings.Create();
        /// <summary>
        /// 光晕设定
        /// </summary>
        public IFlareSettings FlareSettings => flareSettings;
        
        /// <summary>
        /// 光晕的淡化速度
        /// <para>* 场景中所有光晕的淡化速度</para>
        /// </summary>
        public float FlareFadeSpeed 
        {
            get => flareSettings.FadeSpeed;
            set => flareSettings.FadeSpeed = value;
        }
        
        /// <summary>
        /// 光晕强度
        /// <para>* 场景中所有光晕的强度</para>
        /// </summary>
        public float FlareStrength 
        {
            get => flareSettings.Strength;
            set => flareSettings.Strength = value;
        }

#endregion

#region Fog

        [SerializeField, GroupView("雾效设定")]
        private FogSettings fogSettings = Data.FogSettings.Create();
        /// <summary>
        /// 雾效设定
        /// </summary>
        public IFogSettings FogSettings => fogSettings;
        
        /// <summary>
        /// 雾效模式
        /// <para>* 另请参阅：RenderSettings.fogMode、Lighting 窗口。</para>
        /// </summary>
        public FogMode FogMode 
        {
            get => fogSettings.Mode;
            set => fogSettings.Mode = value;
        }
        
        /// <summary>
        /// 无效开启标志位
        /// </summary>
        public bool Fog 
        {
            get => fogSettings.Fog;
            set => fogSettings.Fog = value;
        }
        
        /// <summary>
        /// 雾效颜色
        /// </summary>
        public Color FogColor 
        {
            get => fogSettings.Color;
            set => fogSettings.Color = value;
        }
        
        /// <summary>
        /// 雾效强度
        /// <para>* Exponential 和 ExponentialSquared 模式会使用雾效强度。</para>
        /// </summary>
        public float FogDensity 
        {
            get => fogSettings.Density;
            set => fogSettings.Density = value;
        }
        
        /// <summary>
        /// 雾效开始距离
        /// <para>* Linear 雾效模式会使用雾效开始和结束距离。</para>
        /// <para>* 另请参阅：RenderSettings.fogEndDistance、RenderSettings.fogMode。</para>
        /// </summary>
        public float FogStartDistance 
        {
            get => fogSettings.StartDistance;
            set => fogSettings.StartDistance = value;
        }
        
        /// <summary>
        /// 雾效结束距离
        /// <para>* Linear 雾效模式会使用雾效开始和结束距离。</para>
        /// <para>* 另请参阅：RenderSettings.fogEndDistance、RenderSettings.fogMode。</para>
        /// </summary>
        public float FogEndDistance 
        {
            get => fogSettings.EndDistance;
            set => fogSettings.EndDistance = value;
        }

#endregion

#region ReflectionSettings

        [SerializeField, GroupView("反射设定")]
        private ReflectionSettings reflectionSettings = Data.ReflectionSettings.Create();
        /// <summary>
        /// 反射设定
        /// </summary>
        public IReflectionSettings ReflectionSettings => reflectionSettings;
        
        /// <summary>
        /// 默认反射模式
        /// <para>* Unity 可以使用自定义纹理或从天空盒中生成镜面反射纹理。</para>
        /// </summary>
        public DefaultReflectionMode DefaultReflectionMode 
        {
            get => reflectionSettings.DefaultMode;
            set => reflectionSettings.DefaultMode = value;
        }
        
        /// <summary>
        /// 反射包含其他反射的次数。
        /// <para>* 定义有多少通道计算了反射。在一个给定通道中，场景会渲染到一个立方体贴图中，并将在上个通道中计算的反射应用到反射对象。</para>
        /// <para>* 如果设置为 1，场景将被渲染一次。这意味着反射将不能反射其他反射，并且当在其他反射表面看到反射对象时，反射对象将显示为黑色。</para>
        /// <para>* 如果设置为 2，场景将被渲染两次，并且当在其他反射表面看到反射对象时，反射对象会显示来自第一个通道的反射。</para>
        /// </summary>
        public int ReflectionBounces 
        {
            get => reflectionSettings.Bounces;
            set => reflectionSettings.Bounces = value;
        }
        
        /// <summary>
        /// 反射强度
        /// <para>* 天空盒/自定义立方体贴图反射会对场景产生多大的影响。</para>
        /// </summary>
        public float ReflectionIntensity 
        {
            get => reflectionSettings.Intensity;
            set => reflectionSettings.Intensity = value;
        }

#endregion

        [SerializeField, GenericField("光环的大小", null, "对于任何光照，光环的大小是此值乘以 Light.range。")]
        private float haloStrength = 0.0f;
        /// <summary>
        /// Light 光环的大小。
        /// <para>* 对于任何光照，光环的大小是此值乘以 Light.range。</para>
        /// </summary>
        public float HaloStrength
        {
            get => haloStrength;
            private set => haloStrength = value;
        }
        
        [SerializeField, GenericField("SubtractiveShadowColor", null, "Subtractive 光照模式下太阳阴影使用的颜色。")]
        private Color subtractiveShadowColor = Color.clear;
        /// <summary>
        /// Subtractive 光照模式下太阳阴影使用的颜色
        /// </summary>
        public Color SubtractiveShadowColor 
        {
            get => subtractiveShadowColor;
            private set => subtractiveShadowColor = value;
        }

        /// <summary>
        /// 有效标志位
        /// </summary>
        public override bool Valid => !string.IsNullOrEmpty(sceneName);

#region Equals

        /// <summary>
        /// 比较
        /// </summary>
        /// <param name="iSceneName">场景名</param>
        /// <returns>true:相同; false:不相同;</returns>
        public bool Equals(string iSceneName)
        {
            if (string.IsNullOrEmpty(iSceneName)) return false;
            return !UtilsString.Diff(sceneName, iSceneName);
        }

        /// <summary>
        /// 比较
        /// </summary>
        /// <param name="iSettings">设定信息</param>
        /// <returns>true:相同; false:不相同;</returns>
        public bool Equals(SceneRenderSettingsData iSettings)
        {
            if (null == iSettings || !iSettings.Valid) return false;
            return !UtilsString.Diff(sceneName, iSettings.SceneName);
        }

#endregion

        /// <summary>
        /// 应用数据
        /// </summary>
        /// <param name="iData">数据</param>
        /// <param name="iImport">导入标志位(true:从相应的*.json文件导入; false:反之;)</param>
        /// <returns>true:有变更; false:无变更;</returns>
        public override bool ApplyData(IJsonData iData, bool iImport = false)
        {
            if (null == iData || !iData.Valid) return false;
            var dirty = base.ApplyData(iData, iImport);
            if (dirty && !iImport)
            {
                Dirty = true;
            }

            if (iData is ISceneRenderSettingsData settings)
            {
                sceneName = UpdateValue(sceneName, settings.SceneName, iImport);
                
                dirty = ambientSettings.ApplyData(settings.AmbientSettings);
                if (dirty && !iImport)
                {
                    Dirty = true;
                }
                
                dirty = flareSettings.ApplyData(settings.FlareSettings);
                if (dirty && !iImport)
                {
                    Dirty = true;
                }
                
                dirty = fogSettings.ApplyData(settings.FogSettings);
                if (dirty && !iImport)
                {
                    Dirty = true;
                }
                
                dirty = reflectionSettings.ApplyData(settings.ReflectionSettings);
                if (dirty && !iImport)
                {
                    Dirty = true;
                }

                haloStrength = UpdateValue(haloStrength, settings.HaloStrength, iImport);
                subtractiveShadowColor = UpdateValue(subtractiveShadowColor, settings.SubtractiveShadowColor, iImport);
            }

            return Dirty;
        }

        /// <summary>
        /// 清空
        /// </summary>
        public override void Clear()
        {
            base.Clear();
            
            sceneName = null;
            ambientSettings.Clear();
            flareSettings.Clear();
            fogSettings.Clear();
            reflectionSettings.Clear();
            
            haloStrength = 0.0f;
            subtractiveShadowColor = Color.clear;
        }
    }

    /// <summary>
    /// 场景渲染设定列表
    /// </summary>
    [Serializable]
    public class SceneRenderSettingsList : SAssetListData<SceneRenderSettingsList, SceneRenderSettingsData>, ISceneRenderSettingsList<SceneRenderSettingsData>
    {
        /// <summary>
        /// 保存设定
        /// </summary>
        /// <param name="iSettings">设定信息</param>
        /// <returns>true:OK; false:NG;</returns>
        public bool SaveSettings(SceneRenderSettingsData iSettings)
        {
            if (null == iSettings || !iSettings.Valid) return false;
            if (0 >= Count)
            {
                list.Add(iSettings);
                return true;
            }

            SceneRenderSettingsData targetSettings = null; 
            var count = Count;
            for (var idx = 0; idx < count; ++idx)
            {
                var loop = list[idx];
                if(null == loop || !loop.Valid || !loop.Equals(iSettings)) continue;

                targetSettings = loop;
                break;
            }

            if (null != targetSettings)
            {
                targetSettings.ApplyData(iSettings);
                return true;
            }
            
            // 追加
            list.Add(iSettings);
            
            // 重排序
            list = list.OrderBy(iO => iO.SceneName).ToList();
            return true;
        }

        /// <summary>
        /// 取得场景设定信息
        /// </summary>
        /// <param name="iSceneName">场景名</param>
        /// <returns>场景设定信息</returns>
        public SceneRenderSettingsData GetSettings(string iSceneName)
        {
            if (string.IsNullOrEmpty(iSceneName)) return null;
            
            SceneRenderSettingsData targetSettings = null; 
            var count = Count;
            for (var idx = 0; idx < count; ++idx)
            {
                var loop = list[idx];
                if(null == loop || !loop.Valid || !loop.Equals(iSceneName)) continue;

                targetSettings = loop;
                break;
            }

            if (null == targetSettings)
            {
                this.Warning("GetSettings():该场景渲染设定信息不存在，请确认并收集!(Scene:{0})\n菜单 : Tools -> {1} -> 采样 -> 场景渲染设定。", 
                    iSceneName, Const.HK_LIB_NAME);
            }

            return targetSettings;
        }
    }
}
